package com.good.shopping.product.redis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.good.shopping.product.vo.Catelog2Vo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 4 .分布式锁
 *       RLock 优化 redis2 写法
 * @author shengren.yan
 * @create 2022-02-24
 */
public class redis4 {

    // redis
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    // 分布式锁
    @Autowired
    RedissonClient redisson;

    /**
     * 从数据库查询并封装数据::分布式锁
     * 缓存里的数据如何和数据库的数据保持一致？
     * 缓存数据一致性
     * 1)、双写模式  - 更新数据库时，也更新一下缓存
     * 2)、失效模式  - 更新数据库时，清除缓存
     *  优化 在 redis5 使用读写锁
     * @return
     */
    public Map<String, List<Catelog2Vo>> getCatalogJsonFromDbWithRedisLock() {

        //1、占分布式锁。去redis占坑  catalogJSON-lock 锁名
        RLock lock = redisson.getLock("catalogJSON-lock");
        lock.lock();

        System.out.println("获取分布式锁成功...");
        Map<String, List<Catelog2Vo>> dataFromDb = null;
        try {
            //加锁成功...执行业务
            dataFromDb = getDataFromDb();
        } finally {
            // 释放锁
            lock.unlock();

        }

        return dataFromDb;
    }


    // 查询数据库
    private Map<String, List<Catelog2Vo>> getDataFromDb() {
        //得到锁以后，我们应该再去缓存中确定一次，如果没有才需要继续查询   catalogJson 缓存数据
        String catalogJson = stringRedisTemplate.opsForValue().get("catalogJson");
        if (!StringUtils.isEmpty(catalogJson)) {
            //缓存不为空直接返回
            Map<String, List<Catelog2Vo>> result = JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catelog2Vo>>>() {

            });
            return result;
        }

        System.out.println("查询了数据库");

        //1、查出所有分类

        // 封装数据 -- 模拟查询数据库
        Map<String, List<Catelog2Vo>> parentCid = null;

        //3、将查到的数据放入缓存,将对象转为json  catalogJson 缓存数据
        String valueJson = JSON.toJSONString(parentCid);
        stringRedisTemplate.opsForValue().set("catalogJson", valueJson, 1, TimeUnit.DAYS);

        return parentCid;
    }

}
